package com.agile.leetcode.jvm.objectreference;

import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 在系统将要发生内存溢出异常前，会把这些对象列入回收范围内进行第二次回收。
 * 如果这次回收仍没有足够的内存，才会抛出内存溢出异常。
 * 当内存不足时，JVM 首先将软引用中的对象引用置为 null，然后通知垃圾回收器进行回收
 *
 * @Author:ChenZhangKun
 * @Date: 2021/10/11 22:28
 */
public class SoftReferenceDemo {
    public static void main(String[] args) throws InterruptedException {
        // 创建软引用
        // 此处代码先创建了一个Object类型的对象，
        // 然后使用SoftReference对这个新建对象进行 “描述包装”，
        // 如此这个新建对象就只处于软引用状态
        SoftReference<Object> softReference = new SoftReference<>(new Object());
        // 处于软引用状态的对象，可以使用SoftReference对象的get方法获取
        // 如果不想给对象添加其他引用状态，那么只可以使用SoftReference对象的get方法获取
        // SoftReference对象的get方法的返回值 就好比 强引用状态中的变量名
        // 强引用状态中的变量名如何使用，那么SoftReference对象的get方法的返回值就如何使用
        System.out.println(softReference.get());
        System.gc();
        // 注意：实际上 JVM 何时进行 GC 操作并不可控！
        // 我们调用System.gc()方法只是起通知作用，JVM 什么时候扫描回收对象是 JVM 自己根据当前系统的状态决定的。
        // 因此更严谨的做法是休眠等待一段时间再验证 GC 的情况
        TimeUnit.SECONDS.sleep(1);
        // 因为此时系统内存依然充足，因此 JVM 并不会主动的去释放处于软引用的对象
        System.out.println(softReference.get());
        try {
            List<Object> list = new ArrayList<>();
            while (true) {
                list.add(new Object());
            }
        } catch (Error error) {
            // Java heap space
            System.out.println(error.getMessage());
            // null 此时内存不足会将软应用的内存回收
            System.out.println(softReference.get());
        }
    }
}
